package com.briup.facade.service.impl;

import com.briup.common.exception.CustomerException;
import com.briup.common.properties.ZookeeperProperties;
import com.briup.common.web.MessageStatus;
import com.briup.common.web.SecurityUtil;
import com.briup.dataset.entity.extend.ClassifyEx;
import com.briup.dataset.entity.extend.DataSetEx;
import com.briup.dataset.mapper.extend.DataSetExtendMapper;
import com.briup.dataset.service.IDatasetService;
import com.briup.facade.service.IFascadeEvaluateService;
import com.briup.model.entity.Evaluate;
import com.briup.model.entity.EvaluateLabel;
import com.briup.model.entity.Model;
import com.briup.model.entity.TrainingLabel;
import com.briup.model.entity.extend.TraningEx;
import com.briup.model.mapper.EvaluateLabelMapper;
import com.briup.model.mapper.EvaluateMapper;
import com.briup.model.mapper.ModelMapper;
import com.briup.model.mapper.extend.ModelExtendMapper;
import com.briup.model.mapper.extend.TrainingLabelExtendMapper;
import com.briup.model.service.IModelService;
import com.briup.model.vo.EvaluateVo;
import com.briup.model.vo.TrainingLabelVo;
import com.briup.model.vo.ZookeeperEvaluateVo;
import com.briup.upload.service.IRecoverImageService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.curator.framework.CuratorFramework;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * facade的评估服务
 */
@Service
public class FascadeEvaluateServiceImpl implements IFascadeEvaluateService {
    @Autowired
    private EvaluateMapper evaluateMapper;
    @Autowired
    private EvaluateLabelMapper evaluateLabelMapper;
    @Autowired
    private ModelMapper modelMapper;
    @Autowired
    private ModelExtendMapper modelExtendMapper;
    @Autowired
    private IModelService modelService;
    @Autowired
    private TrainingLabelExtendMapper trainingLabelExtendMapper;
    @Autowired
    private DataSetExtendMapper dataSetExtendMapper;
    @Autowired
    private IDatasetService datasetService;
    @Autowired
    private IRecoverImageService recoverImageService;
    @Autowired
    private CuratorFramework client;
    @Autowired
    private ZookeeperProperties zookeeperProperties;

    @Transactional
    @Override
    public Integer insertEvaluate(Evaluate evaluate) {
        int evaluateId = evaluateMapper.insert(evaluate);
        return evaluate.getId();
    }
    @Transactional
    @Override
    public void insertEvaluateLabel(Integer evaluateId, List<EvaluateLabel> evaluateLabelList) {
        evaluateLabelList.forEach(evaluateLabel -> {
            evaluateLabel.setEvaluateId(evaluateId);
            evaluateLabelMapper.insertSelective(evaluateLabel);
        });
    }

    @Transactional
    @Override
    public void evaluateTraining(EvaluateVo evaluateVo, Integer modelId) {
        // 0.---评估的数据集下的分类数量和名称要和训练时的数据集下的分类数量和名称一致---
        // 查找训练使用的分类信息
        // 通过最新版本和模型id定位到最新训练记录
        String lastModelVersion = evaluateVo.getLastModelVersion();
        Integer datasetId = evaluateVo.getDatasetId();
        TraningEx traningEx = modelExtendMapper.findTraningExByModelIdAndVersion(modelId, lastModelVersion);
        List<TrainingLabelVo> trainingLabelVoList = trainingLabelExtendMapper.findClassifyVoByTrainingId(traningEx.getId());

        // 查找评估所用数据的的分类名称信息
        List<String> classNameList = dataSetExtendMapper.selectClassifyNameByDatasetId(datasetId);

        // 比对两者的数量和分类名称是否相同
        //比较分类数量
        if (trainingLabelVoList.size() != classNameList.size()) {
            throw new CustomerException(MessageStatus.EVALUATE_DATASET_ERROR);
        }
        //比较分类名称
        for (int i = 0; i < classNameList.size(); i++) {
            if (!classNameList.get(i).equals(trainingLabelVoList.get(i).getLabelName())) {
                throw new CustomerException(MessageStatus.EVALUATE_DATASET_ERROR);
            }
        }
        // 2.----------------还原数据集----------------
        // 还原数据集
        recoverImageService.recoverImage(datasetId);
        // 3.---------------封装zookeeper--------------
        ZookeeperEvaluateVo zookeeperEvaluateVo = fillZookeeperEvaluateVo(classNameList,traningEx,evaluateVo,modelId);

        ObjectMapper objectMapper = new ObjectMapper();
        String zookeeperEvluateVoJson = null;
        try {
            zookeeperEvluateVoJson = objectMapper.writeValueAsString(zookeeperEvaluateVo);
            client.setData().forPath(zookeeperProperties.getTaskPath(), zookeeperEvluateVoJson.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 3.---------------封装zookeeper完成--------------

    }

    private ZookeeperEvaluateVo fillZookeeperEvaluateVo(List<String> classNameList, TraningEx traningEx, EvaluateVo evaluateVo, Integer modelId) {
        String taskId = UUID.randomUUID().toString();
        Model model = modelMapper.selectByPrimaryKey(modelId);
        ZookeeperEvaluateVo zookeeperEvaluateVo = new ZookeeperEvaluateVo();
        zookeeperEvaluateVo.setErrorImagePath("media/errorimages/" + traningEx.getId());
        zookeeperEvaluateVo.setOldModelPath(traningEx.getModelFileaddr());
        zookeeperEvaluateVo.setUserId(Integer.parseInt(SecurityUtil.getUserId()));
        zookeeperEvaluateVo.setTaskId(taskId);
        zookeeperEvaluateVo.setTaskTime(new Date());
        zookeeperEvaluateVo.setTaskType(evaluateVo.getTaskType());
        zookeeperEvaluateVo.setDatasestId(evaluateVo.getDatasetId());
        zookeeperEvaluateVo.setTrainingId(traningEx.getId());
        zookeeperEvaluateVo.setDatasetAddress("Intergrationfiles/" + taskId);
        zookeeperEvaluateVo.setModelName(model.getModelName());
        zookeeperEvaluateVo.setStatus(0);
        zookeeperEvaluateVo.setClassNameList(classNameList);
        return zookeeperEvaluateVo;
    }

    // 评估之前查找模型训练所用数据集分类 有可能训练使用了多个数据，而评估只使用了一个数据集
    @Override
    public Map<String, Object> findClassifysInTraning(Integer modelId) {
        // 如果有满足条件的数据集,返回数据集Id,没有就返回分类名称和数量
        Map<String, Object> map = new HashMap<>();

        // 查询所有数据集下的分类信息
        List<DataSetEx> dataSetExList = datasetService.selectDataSetExList();
        // 查询最新训练所使用的数据集以及分类信息
        Map<String, Object> modelInfo = modelService.modelInfo(modelId);
        TraningEx traningEx = (TraningEx) modelInfo.get("traningEx");
        // 训练所用的分类
        List<TrainingLabel> trainingLabel = traningEx.getTrainingLabel();
        // 满足条件的数据集id
        Map<Integer,String> enabledDataSet = new HashMap<>();
        dataSetExList.forEach(dataSetEx -> {
            List<ClassifyEx> classifyExList = dataSetEx.getClassifyExList();
            if (classifyExList.size() == trainingLabel.size()) {
                // 分类数量相等
                for (int i = 0; i < classifyExList.size(); i++) {
                    // 分类名称相等
                    if (classifyExList.get(i).getClassifyName().equals(trainingLabel.get(i).getLabelName())) {
                        enabledDataSet.put(dataSetEx.getId(),dataSetEx.getDatasetName());
                    }
                }
            }
        });
        // 如果有可匹配的数据集 直接返回
        if (enabledDataSet.size() != 0) {
            map.put("enabledDataSet",enabledDataSet);
        }else{
            // 没有匹配的数据集 ，返回分类名称 自己再根据名称造一个数据集
            List<String> LabelNameList = new ArrayList<>();
            trainingLabel.forEach(label->{
                LabelNameList.add(label.getLabelName());
            });
            map.put("LabelNameList",LabelNameList);
        }
        return map;
    }

}
